/**
 *  Copyright (C) 2006 zhangbo (freeeob@gmail.com)
 *
 *  This product is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 * 
 *  This product is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 *
 *  author:zhangbo
 *  Email:jsjava@gmail.com
 */
 
 /**  The PolynomialSplineFunction class references to org.apache.commons.math.analysis.PolynomialSplineFunction */
 
/**
 * Construct a polynomial spline function with the given segment delimiters
 * and interpolating polynomials.
 * <p>
 * The constructor copies both arrays and assigns the copies to the knots
 * and polynomials properties, respectively.
 * 
 * @param knots spline segment interval delimiters
 * @param polynomials polynomial functions that make up the spline
 * @throws NullPointerException if either of the input arrays is null
 * @throws IllegalArgumentException if knots has length less than 2,  
 * <code>polynomials.length != knots.length - 1 </code>, or the knots array
 * is not strictly increasing.
 * 
 */
function PolynomialSplineFunction(knots,polynomials){
	this.jsjava_class="jsorg.apache.commons.math.analysis.PolynomialSplineFunction";
	if (knots.length < 2) {
        throw new IllegalArgumentException
            (IllegalArgumentException.ERROR,"Not enough knot values -- spline partition must have at least 2 points.");
    }
    if (knots.length - 1 != polynomials.length) {
        throw new IllegalArgumentException 
        (IllegalArgumentException.ERROR,"Number of polynomial interpolants must match the number of segments.");
    }
    if (!PolynomialSplineFunction.isStrictlyIncreasing(knots)) {
        throw new IllegalArgumentException 
            (IllegalArgumentException.ERROR,"Knot values must be strictly increasing.");
    }
    
    this.n = knots.length -1;
    this.knots = new Array(this.n + 1);
    for(var i=0;i<knots.length;i++){
    	this.knots[i]=knots[i];
    }
    this.polynomials = new Array(this.n);
    for(var i=0;i<polynomials.length;i++){
    	this.polynomials[i]=polynomials[i];
    }
}

/**
 * Returns the derivative of the polynomial spline function as a UnivariateRealFunction
 */
PolynomialSplineFunction.prototype.derivative=function(){
	return this.polynomialSplineDerivative();
};

/**
 * Returns an array copy of the knot points.
 */
PolynomialSplineFunction.prototype.getKnots=function(){
	var out = new Array(this.n + 1);
    for(var i=0;i<out.length;i++){
    	out[i]=this.knots[i];
    }
    return out;
};

/**
 *  Returns a copy of the interpolating polynomials array.
 */
PolynomialSplineFunction.prototype.getPolynomials=function(){
	var p = new Array(this.n);
    for(var i=0;i<p.length;i++){
    	p[i]=this.polynomials[i];
    }
    return p;
};

/**
 * Returns the derivative of the polynomial spline function as a PolynomialSplineFunction
 */
PolynomialSplineFunction.prototype.polynomialSplineDerivative=function(){
	var derivativePolynomials = new Array(this.n);
    for (var i = 0; i < this.n; i++) {
        derivativePolynomials[i] = this.polynomials[i].polynomialDerivative();
    }
    return new PolynomialSplineFunction(this.knots, derivativePolynomials);
};

/**
 * Compute the value for the function.
 */
PolynomialSplineFunction.prototype.value=function(v){
	if (v < this.knots[0] || v > this.knots[this.n]) {
        throw new FunctionEvaluationException(FunctionEvaluationException.ERROR,"Argument outside domain");
    }
    var i=-1;
    for(var m=0;m<this.knots.length;m++){
    	if(v==this.knots[m]){
    		i=m;
    		break;
    	}
    }
    if (i < 0) {
        i = -i - 2;
    }
    if ( i >= this.polynomials.length ) {
        i--;
    }
    return this.polynomials[i].value(v - this.knots[i]);
};

/**
 * Determines if the given array is ordered in a strictly increasing
 * fashion.
 * 
 * @param x the array to examine.
 * @return <code>true</code> if the elements in <code>x</code> are ordered
 * in a stricly increasing manner.  <code>false</code>, otherwise.
 */
PolynomialSplineFunction.isStrictlyIncreasing=function(arr) {
    for (var i = 1; i < arr.length; ++i) {
        if (arr[i - 1] >= arr[i]) {
            return false;
        }
    }
    return true;
};